﻿/*
* This software is licensed under the GNU General Public License, version 2
* You may copy, distribute and modify the software as long as you track changes/dates of in source files and keep all modifications under GPL. You can distribute your application using a GPL library commercially, but you must also provide the source code.

* DNNspot Software (http://www.dnnspot.com)
* Copyright (C) 2013 Atriage Software LLC
* Authors: Kevin Southworth, Matthew Hall, Ryan Doom

* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.

* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.

* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

* Full license viewable here: http://www.gnu.org/licenses/gpl-2.0.txt
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WA.FileHelpers.Csv;
using System.IO;
using DotNetNuke.Entities.Modules;
using EntitySpaces.Interfaces;
using WA.FileHelpers.Csv;


namespace DNNspot.PropertyAgentImport
{
    public partial class Default : ModuleBase
    {
        #region PageLoad

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                LoadModulesAvailable();
            }
        }

        #endregion

        #region ButtonClicks

        protected void btnSelect_Click(object sender, EventArgs e)
        {
            //ClearErrorMessages();

            //ModuleIdTarget = Convert.ToInt32(ddlPropertyAgentModules.SelectedValue);

            //PropertyTypeQuery q = new PropertyTypeQuery();
            //q.Select().Where(q.ModuleID == ModuleIdTarget).OrderBy(q.Name.Ascending);

            //PropertyTypeCollection propertyTypes = new PropertyTypeCollection();
            //propertyTypes.Load(q);
        }

        protected void btnUpload_Click(object sender, EventArgs e)
        {
            ClearErrorMessages();

            ModuleIdTarget = Convert.ToInt32(ddlPropertyAgentModules.SelectedValue);
            var filePath = SaveCsvFile();
            if (!String.IsNullOrEmpty(filePath))
                ParseCsvFile(filePath);
        }
        
        protected void btnExport_Click(object sender, EventArgs e)
        {
            ClearErrorMessages();

            ModuleIdTarget = Convert.ToInt32(ddlPropertyAgentModules.SelectedValue);

            ExportToCsv();
        }
        
        protected void btnDeleteAll_Click(object sender, EventArgs e)
        {
            ClearErrorMessages();
            ModuleIdTarget = Convert.ToInt32(ddlPropertyAgentModules.SelectedValue);

            bool status = Property.DeleteByModuleId(ModuleIdTarget);

            if (status)
            {
                litDeleteError.Text = "Properties successfully deleted";
            }
            else
            {
                litDeleteError.Text = "Unable to delete properties";
            }
        }


    #endregion

        #region HelperFunctions

        private void LoadModulesAvailable()
        {
            List<TabModuleMatch> modules = DNNspot.PropertyAgentImport.DnnHelper.GetTabsWithModuleByModuleName(PortalId, "PropertyAgent");

            if (modules.Count > 0)
            {
                ddlPropertyAgentModules.DataSource = modules;
                ddlPropertyAgentModules.DataValueField = "ModuleId";
                ddlPropertyAgentModules.DataTextField = "DisplayName";
                ddlPropertyAgentModules.DataBind();

                ddlPropertyAgentModules.Items.Insert(0, new ListItem { Text = "Select a Module", Value = String.Empty, Selected = true });
            }
        }

        private void ClearErrorMessages()
        {
            litUploadMessage.Text = String.Empty;
            litUploadError.Text = String.Empty;
            litMessage.Text = String.Empty;
            litExportError.Text = String.Empty;
            litDeleteError.Text = String.Empty;
        }

        private String SaveCsvFile()
        {
            if (!fuCsvFile.HasFile)
                return "Please select a CSV file to be uploaded.";

            var filePath = Server.MapPath(String.Format("{0}/uploads/{1}", ModuleWebPath, fuCsvFile.FileName));
            fuCsvFile.SaveAs(filePath);

            return filePath;
        }


        private void ParseCsvFile(string filePath)
        {
            var csvOptions = new CsvReaderOptions() { HasHeaderRecord = true, Strict = false };
            var parser = new CsvParser(new StreamReader(filePath));
            var reader = new CsvReader(parser, csvOptions);


            // Get customField Dictionary
            Dictionary<string, int?> customFieldsDictionary = GetCustomFieldsNamesDictionary(ModuleIdTarget);

            // Get propertyType dictionary
            Dictionary<string, int?> propertyTypesDictionary = GetPropertyTypesNamesDictionary(ModuleIdTarget);

            List<string> importErrors = new List<string>();

            try
            {
                //int defaultProperty = Convert.ToInt32(ddlDefaultProperty.SelectedValue);
                int i = 1;

                // Add new markers to db from csv
                while (reader.Read())
                {
                    var property = new Property();
                    
                    string column = String.Empty;

                    try
                    {

                        i++;
                        if (propertyTypesDictionary.ContainsKey(reader.GetField("PropertyType")))
                        {
                            property.PropertyTypeID = propertyTypesDictionary[reader.GetField("PropertyType")];
                        }
                        else
                        {
                            // Just use a default specified property
                            //property.PropertyTypeID = defaultProperty;

                            
                            // Create a new property if not there

                            // Get Sort Order
                            PropertyTypeCollection propertyTypes = new PropertyTypeCollection();
                            PropertyTypeQuery propertyTypeQuery = new PropertyTypeQuery();

                            propertyTypeQuery.Where(propertyTypeQuery.ModuleID == ModuleIdTarget).OrderBy(propertyTypeQuery.SortOrder.Descending);
                            propertyTypes.Load(propertyTypeQuery);

                            int sortOrder = propertyTypes.FirstOrDefault() != null ? propertyTypes.FirstOrDefault().SortOrder.Value + 1 : 1;

                            PropertyType propertyType = new PropertyType
                                                            {
                                                                Name = reader.GetField("PropertyType"),
                                                                ModuleID = ModuleIdTarget,
                                                                ParentID = -1,
                                                                SortOrder = sortOrder,
                                                                IsPublished = true,
                                                                AllowProperties = true,
                                                            };

                            propertyType.Save();
                            propertyTypesDictionary[reader.GetField("PropertyType")] = propertyType.PropertyTypeID;

                            property.PropertyTypeID = propertyTypesDictionary[reader.GetField("PropertyType")];

                            
                        }

                        property.DatePublished = !String.IsNullOrEmpty(reader.GetField("DatePublished")) ? Convert.ToDateTime(reader.GetField("DatePublished")) : DateTime.Now;
                        property.IsFeatured = true;
                        property.DateCreated = DateTime.Now;
                        property.DateModified = DateTime.Now;
                        property.ViewCount = 0;
                        property.Status = 3;
                        property.AuthorID = UserId;
                        property.Rating = 0;
                        property.RatingCount = 0;
                        property.CommentCount = 0;
                        property.ModifiedID = 1;
                        property.ModuleID = ModuleIdTarget;

                        property.Save();

                        foreach (KeyValuePair<string, int?> dictPair in customFieldsDictionary)
                        {
                            PropertyValue propertyValue = new PropertyValue();
                            propertyValue.CustomFieldID = dictPair.Value;
                            propertyValue.PropertyID = property.PropertyID;
                            column = dictPair.Key;
                            propertyValue.CustomValue = !String.IsNullOrEmpty(reader.GetField(dictPair.Key)) ? reader.GetField(dictPair.Key) : String.Empty;
                            propertyValue.Save();
                        }

                        if (importErrors.Count > 0)
                        {
                            litUploadMessage.Text = "Some or all of the properties were successfully imported. Errors:";
                        }
                        else
                        {
                            litUploadMessage.Text = "All properties were successfully imported.";
                        }

                    }
                    catch (Exception ex)
                    {
                        importErrors.Add("Row: " + i.ToString() + " Error: " + ex.Message + " Column:" + column);
                    }
                }


            }
            catch (Exception ex)
            {
                litUploadError.Text = String.Format("Error: {0}, {1}", ex.Message, ex.StackTrace);
            }

            litUploadError.Text += String.Join("<br />", importErrors.ToArray());
            reader.Dispose();
        }

        private void ExportToCsv()
        {
            var properties = new PropertyCollection();
            var q = new PropertyQuery();

            q.SelectAll().Where(q.ModuleID == ModuleIdTarget).OrderBy(q.PropertyID.Ascending);
            properties.Load(q);

            // Custom Fields and Property Types Dictionaries
            var customFieldsDictionary = GetCustomFieldsIdDictionary(ModuleIdTarget);
            var propertyTypesDictionary = GetPropertyTypesIdDictionary(ModuleIdTarget);

            Response.Clear();
            Response.ClearHeaders();
            Response.ContentType = "text/csv";
            string file = "attachment; filename=" + "PropertyExport-" + ModuleIdTarget.ToString() + ".csv";
            Response.AddHeader("Content-Disposition", file);

            List<string> importErrors = new List<string>();

            using (var writer = new StreamWriter(Response.OutputStream))
            {
                try
                {
                    var csv = new CsvWriter(writer, new CsvWriterOptions { HasHeaderRecord = true });
                    // write headers

                    customFieldsDictionary.OrderBy(a => a.Key);

                    foreach (KeyValuePair<int?, string> p in customFieldsDictionary)
                    {
                        csv.WriteField(p.Value);
                    }

                    csv.WriteField("PropertyType");

                    csv.NextRecord();

                    // write each field for each row);

                    foreach (Property property in properties)
                    {
                        try
                        {
                            PropertyValueCollection propertyValues = property.PropertyValueCollectionByPropertyID;

                            foreach (KeyValuePair<int?, string> p in customFieldsDictionary)
                            {
                                var value = propertyValues.Where(a => a.CustomFieldID == p.Key).FirstOrDefault();
                                string actualValue = String.Empty;
                                if (value != null)
                                {
                                    actualValue = value.CustomValue.ToString();
                                }
                                csv.WriteField(actualValue);
                            }

                            if (property.PropertyTypeID != null)
                                csv.WriteField(propertyTypesDictionary[property.PropertyTypeID]);

                            csv.NextRecord();
                        }
                        catch (Exception ex)
                        {
                            importErrors.Add("Property ID: " + property.PropertyID.ToString() + " Error: " + ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    litExportError.Text = String.Format("Error: {0}, {1}", ex.Message, ex.StackTrace);
                }

                litExportError.Text += String.Join("<br />", importErrors.ToArray());
            }

            Response.Flush();
            Response.End();
        }

        #endregion

        #region DictionaryFunctions

        public Dictionary<string, int?> GetPropertyTypesNamesDictionary(int moduleIdTarget)
        {
            PropertyTypeQuery pt = new PropertyTypeQuery();
            pt.SelectAll().Where(pt.ModuleID == moduleIdTarget);
            PropertyTypeCollection propertyTypes = new PropertyTypeCollection();
            propertyTypes.Load(pt);

            Dictionary<string, int?> propertyTypesDictionary = new Dictionary<string, int?>();

            foreach (PropertyType p in propertyTypes)
            {
                propertyTypesDictionary[p.Name] = p.PropertyTypeID;
            }
            return propertyTypesDictionary;
        }


        public Dictionary<int?, string> GetPropertyTypesIdDictionary(int moduleIdTarget)
        {
            PropertyTypeQuery pt = new PropertyTypeQuery();
            pt.SelectAll().Where(pt.ModuleID == moduleIdTarget);
            PropertyTypeCollection propertyTypes = new PropertyTypeCollection();
            propertyTypes.Load(pt);

            Dictionary<int?, string> propertyTypesDictionary = new Dictionary<int?, string>();

            foreach (PropertyType p in propertyTypes)
            {
                if (p.PropertyTypeID != null)
                    propertyTypesDictionary[p.PropertyTypeID] = p.Name;
            }
            return propertyTypesDictionary;
        }

        public Dictionary<string, int?> GetCustomFieldsNamesDictionary(int moduleIdTarget)
        {
            CustomFieldQuery q = new CustomFieldQuery();
            q.SelectAll().Where(q.ModuleID == moduleIdTarget);
            CustomFieldCollection customFields = new CustomFieldCollection();
            customFields.Load(q);

            Dictionary<string, int?> customFieldsDictionary = new Dictionary<string, int?>();
            foreach (CustomField cf in customFields)
            {
                customFieldsDictionary[cf.Name] = cf.CustomFieldID;
            }
            return customFieldsDictionary;
        }


        public Dictionary<int?, string> GetCustomFieldsIdDictionary(int ModuleIdTarget)
        {
            CustomFieldQuery q = new CustomFieldQuery();
            q.SelectAll().Where(q.ModuleID == ModuleIdTarget);
            CustomFieldCollection customFields = new CustomFieldCollection();
            customFields.Load(q);

            Dictionary<int?, string> customFieldsDictionary = new Dictionary<int?, string>();
            foreach (CustomField cf in customFields)
            {
                if (cf.CustomFieldID != null)
                    customFieldsDictionary[cf.CustomFieldID] = cf.Name;
            }
            return customFieldsDictionary;
        }

        #endregion
    }
}